# Linux modprobe(8) completion                             -*- shell-script -*-

_modprobe()
{
    local cur prev words cword split
    _init_completion -s || return

    case "$prev" in
        --help | --version | -!(-*)[hV])
            return
            ;;
        --config | -!(-*)C)
            _filedir
            return
            ;;
        --dirname | --type | -!(-*)[dt])
            _filedir -d
            return
            ;;
        --set-version | -!(-*)S)
            _kernel_versions
            return
            ;;
    esac

    $split && return

    if [[ $cur == -* ]]; then
        COMPREPLY=($(compgen -W '$(_parse_help "$1")' -- "$cur"))
        if [[ ! ${COMPREPLY-} ]]; then
            COMPREPLY=($(compgen -W '-a --all -b --use-blacklist -C --config
                -c --showconfig --dump-modversions -d --dirname --first-time
                --force-vermagic --force-modversion -f --force -i
                --ignore-install --ignore-remove -l --list -n --dry-run -q
                --quiet -R --resolve-alias -r --remove -S --set-version
                --show-depends -s --syslog -t --type -V --version -v
                --verbose' -- "$cur"))
        fi
        [[ ${COMPREPLY-} == *= ]] && compopt -o nospace
        return
    fi

    local i mode=insert module="" version=$(uname -r)
    for ((i = 1; i < cword; i++)); do
        case "${words[i]}" in
            --remove | -!(-*)r*)
                mode=remove
                ;;
            --list | -!(-*)l*)
                mode=list
                ;;
            --dump-modversions)
                mode="file"
                ;;
            --set-version | -!(-*)S)
                version=${words[i + 1]} # -S is not $prev and not $cur
                ;;
            --config | --dirname | --type | -!(-*)[Cdt])
                ((i++)) # skip option and its argument
                ;;
            -*)
                # skip all other options
                ;;
            *)
                [[ -z $module ]] && module=${words[i]}
                ;;
        esac
    done

    case $mode in
        remove)
            _installed_modules "$cur"
            ;;
        list)
            # no completion available
            ;;
        file)
            _filedir
            ;;
        insert)
            # do filename completion if we're giving a path to a module
            if [[ $cur == @(*/|[.~])* ]]; then
                _filedir '@(?(k)o?(.[gx]z|.zst))'
            elif [[ -n $module ]]; then
                # do module parameter completion
                if [[ $cur == *=* ]]; then
                    prev=${cur%%=*}
                    cur=${cur#*=}
                    if PATH="$PATH:/sbin" modinfo -p "$module" 2>/dev/null |
                        command grep -q "^$prev:.*(bool)"; then
                        local choices="on off"
                        [[ $cur ]] && choices="1 0 y Y n N on off"
                        COMPREPLY=($(compgen -W "$choices" -- "$cur"))
                    fi
                else
                    COMPREPLY=($(compgen -S = -W "$(PATH="$PATH:/sbin" \
                        modinfo -p "$module" 2>/dev/null |
                        awk -F: '!/^[ \t]/ { print $1 }')" -- "$cur"))
                    [[ ${COMPREPLY-} == *= ]] && compopt -o nospace
                fi
            else
                _modules $version
                if [[ ${COMPREPLY-} ]]; then
                    # filter out already installed modules
                    local -a mods=("${COMPREPLY[@]}")
                    _installed_modules "$cur"
                    for i in "${!mods[@]}"; do
                        for module in "${COMPREPLY[@]}"; do
                            if [[ ${mods[i]} == "$module" ]]; then
                                unset -v 'mods[i]'
                                break
                            fi
                        done
                    done
                    COMPREPLY=("${mods[@]}")
                fi
            fi
            ;;
    esac
} &&
    complete -F _modprobe modprobe

# ex: filetype=sh
